#include "cgns_to_hdf5_convert.h"
#include <cgnslib.h>
#include <H5Cpp.h>
#include <iostream>

using namespace H5;

int CgnsToHdf5Convert::convert(const std::string& cgnsPath, const std::string& hdf5Path) {
    if (readCgnsFile(cgnsPath) != 0) return -1;
    return writeHdf5File(hdf5Path);
}

int CgnsToHdf5Convert::readCgnsFile(const std::string& path) {
    int fileIndex, baseIndex = 1, zoneIndex = 1;

    // 打开 CGNS 文件
    if (cg_open(path.c_str(), CG_MODE_READ, &fileIndex)) {
        std::cerr << "Error opening CGNS file: " << path << std::endl;
        return 1;
    }

    // 获取节点数量
    cgsize_t sizes[3];  // sizes[0] = vertex size, sizes[1] = cell size, sizes[2] = boundary vertex size
    if (cg_zone_read(fileIndex, baseIndex, zoneIndex, nullptr, sizes)) {
        std::cerr << "Error reading zone information." << std::endl;
        cg_close(fileIndex);
        return 1;
    }

    int nNodes = static_cast<int>(sizes[0]);
    nodes.resize(nNodes);
    std::vector<float> x(nNodes), y(nNodes), z(nNodes);

    cgsize_t range_min[1] = {1};
    cgsize_t range_max[1] = {sizes[0]};

    // 读取 X 坐标
    if (cg_coord_read(fileIndex, baseIndex, zoneIndex, "CoordinateX", RealSingle,
                      range_min, range_max, x.data())) {
        std::cerr << "Failed to read CoordinateX" << std::endl;
        cg_close(fileIndex);
        return 1;
    }

    // 读取 Y 坐标
    if (cg_coord_read(fileIndex, baseIndex, zoneIndex, "CoordinateY", RealSingle,
                      range_min, range_max, y.data())) {
        std::cerr << "Failed to read CoordinateY" << std::endl;
        cg_close(fileIndex);
        return 1;
    }

    // 读取 Z 坐标
    if (cg_coord_read(fileIndex, baseIndex, zoneIndex, "CoordinateZ", RealSingle,
                      range_min, range_max, z.data())) {
        std::cerr << "Failed to read CoordinateZ" << std::endl;
        cg_close(fileIndex);
        return 1;
    }

    // 存入节点向量
    for (int i = 0; i < nNodes; ++i) {
        nodes[i] = { x[i], y[i], z[i] };
    }

    cg_close(fileIndex);
    return 0;
}


int CgnsToHdf5Convert::writeHdf5File(const std::string& path) {
    try {
        H5File file(path, H5F_ACC_TRUNC);

        // === 写节点坐标 ===
        if (!nodes.empty()) {
            hsize_t nodeDims[2] = { nodes.size(), 3 };
            DataSpace nodeSpace(2, nodeDims);
            DataSet nodeDataset = file.createDataSet("/mesh/nodes", PredType::NATIVE_FLOAT, nodeSpace);
            nodeDataset.write(nodes.data(), PredType::NATIVE_FLOAT);
        }

        // === 写单元连接 ===
        if (!elements.empty()) {
            size_t maxNodePerElement = 0;
            for (const auto& elem : elements) {
                if (elem.size() > maxNodePerElement) maxNodePerElement = elem.size();
            }

            std::vector<int> flatElements;
            for (const auto& elem : elements) {
                std::vector<int> padded = elem;
                padded.resize(maxNodePerElement, -1); // 用 -1 填充
                flatElements.insert(flatElements.end(), padded.begin(), padded.end());
            }

            hsize_t elemDims[2] = { elements.size(), maxNodePerElement };
            DataSpace elemSpace(2, elemDims);
            DataSet elemDataset = file.createDataSet("/mesh/elements", PredType::NATIVE_INT, elemSpace);
            elemDataset.write(flatElements.data(), PredType::NATIVE_INT);
        }

        // === 写速度场 velocity ===
        if (!velocity.empty()) {
            hsize_t velDims[2] = { velocity.size(), 3 };
            DataSpace velSpace(2, velDims);
            DataSet velDataset = file.createDataSet("/fields/velocity", PredType::NATIVE_FLOAT, velSpace);
            velDataset.write(velocity.data(), PredType::NATIVE_FLOAT);
        }

        // === 写压强场 pressure ===
        if (!pressure.empty()) {
            hsize_t presDims[1] = { pressure.size() };
            DataSpace presSpace(1, presDims);
            DataSet presDataset = file.createDataSet("/fields/pressure", PredType::NATIVE_FLOAT, presSpace);
            presDataset.write(pressure.data(), PredType::NATIVE_FLOAT);
        }

        return 0;
    } catch (const FileIException& e) {
        std::cerr << "HDF5 file error: " << e.getCDetailMsg() << std::endl;
        return -1;
    } catch (const DataSetIException& e) {
        std::cerr << "HDF5 dataset error: " << e.getCDetailMsg() << std::endl;
        return -1;
    } catch (const DataSpaceIException& e) {
        std::cerr << "HDF5 dataspace error: " << e.getCDetailMsg() << std::endl;
        return -1;
    }
}